package com.smasher.widget.view;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.LinearGradient;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Shader;
import android.os.Handler;
import android.os.Looper;
import android.util.AttributeSet;
import android.util.Log;

import androidx.annotation.Nullable;
import androidx.appcompat.widget.AppCompatTextView;

import com.nineoldandroids.animation.Animator;
import com.nineoldandroids.animation.ValueAnimator;
import com.smasher.widget.R;

/**
 * @author Smasher
 * on 2020/3/24 0024
 */
public class ShimmerTextView extends AppCompatTextView {

    public static final String TAG = "ShimmerTextView";

    private final Matrix mMatrix = new Matrix();

    private Paint mPaint;
    private LinearGradient mLinearGradient;
    private ValueAnimator mAnimator;
    private int shimmerColor = Color.parseColor("#FFD600"); // 默认shimmer颜色
    private long shimmerDuration = 2000;
    private long shimmerGap = 1000;

    public ShimmerTextView(Context context) {
        this(context, null);
    }

    public ShimmerTextView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public ShimmerTextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        try (TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ShimmerTextView)) {
            shimmerColor = a.getColor(R.styleable.ShimmerTextView_shimmerColor, shimmerColor);
            shimmerDuration = a.getInt(R.styleable.ShimmerTextView_shimmerDuration, 2000);
            shimmerGap = a.getInt(R.styleable.ShimmerTextView_shimmerGap, 1000);
        } catch (Exception e) {
            Log.e(TAG, "ShimmerTextView: ", e);
        }
        init();
    }

    public void init() {
        mPaint = getPaint();
    }

    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        if (mPaint != null) {
            int length = (int) mPaint.measureText(getText().toString());
            startShimmerAnimation(length);
            createLinearGradient(length);
        }
    }

    @Override
    protected void onDetachedFromWindow() {
        stopShimmerAnimation();
        super.onDetachedFromWindow();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        if (mPaint != null) {
            mPaint.setShader(mLinearGradient);
        }
        super.onDraw(canvas);
    }

    private void createLinearGradient(int length) {
        if (mLinearGradient == null) {
            int[] colors = new int[]{
                    getCurrentTextColor(),
                    shimmerColor,
                    getCurrentTextColor()
            };
            float[] positions = new float[]{
                    0,
                    0.5f,
                    1
            };
            mLinearGradient =
                    new LinearGradient(
                            -length, 0,
                            0, 0,
                            colors, positions, Shader.TileMode.CLAMP
                    );
        }
    }

    private void startShimmerAnimation(int length) {
        if (mAnimator == null) {
            mAnimator = ValueAnimator.ofInt(0, 2 * length);
            mAnimator.addUpdateListener(animation -> {
                int dx = (int) animation.getAnimatedValue();
                mMatrix.setTranslate(dx, 0);
                if (mLinearGradient != null) {
                    mLinearGradient.setLocalMatrix(mMatrix);
                }
                postInvalidate();
            });
            mAnimator.setRepeatMode(ValueAnimator.RESTART);
            //mAnimator.setRepeatCount(ValueAnimator.INFINITE);
            mAnimator.setDuration(shimmerDuration);
            mAnimator.addListener(mAnimatorListener);
        }
        mAnimator.start();
    }


    private void stopShimmerAnimation() {
        if (mAnimator != null && mAnimator.isRunning()) {
            mAnimator.cancel();
        }
    }

    @Override
    protected void onTextChanged(CharSequence text, int start, int lengthBefore, int lengthAfter) {
        super.onTextChanged(text, start, lengthBefore, lengthAfter);
        recreateLinearGradient();
    }

    private void recreateLinearGradient() {
        if (mPaint != null) {
            int length = (int) mPaint.measureText(getText().toString());
            createLinearGradient(length);
            if (mAnimator != null && mAnimator.isRunning()) {
                mAnimator.cancel();
                startShimmerAnimation(length);
            }
        }
    }

    private final ValueAnimator.AnimatorListener mAnimatorListener = new ValueAnimator.AnimatorListener() {

        /**
         * <p>Notifies the start of the animation.</p>
         *
         * @param animation The started animation.
         */
        @Override
        public void onAnimationStart(Animator animation) {

        }

        /**
         * <p>Notifies the end of the animation. This callback is not invoked
         * for animations with repeat count set to INFINITE.</p>
         *
         * @param animation The animation which reached its end.
         */
        @Override
        public void onAnimationEnd(Animator animation) {
            // 这里设置的时间间隔为500毫秒
            new Handler(Looper.getMainLooper()).postDelayed(() -> mAnimator.start(), shimmerGap);
        }

        /**
         * <p>Notifies the cancellation of the animation. This callback is not invoked
         * for animations with repeat count set to INFINITE.</p>
         *
         * @param animation The animation which was canceled.
         */
        @Override
        public void onAnimationCancel(Animator animation) {

        }

        /**
         * <p>Notifies the repetition of the animation.</p>
         *
         * @param animation The animation which was repeated.
         */
        @Override
        public void onAnimationRepeat(Animator animation) {

        }
    };

}
